package com.itheima.aop;

import com.alibaba.fastjson.JSONObject;
import com.itheima.dao.OperateLogMapper;
import com.itheima.pojo.OperateLog;
import com.itheima.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Arrays;

@Component
@Aspect
@Slf4j
public class OperateLogAspect {
    //依赖HttpServletRequest对象
    @Autowired
    private HttpServletRequest request;
    //依赖OperateLogMapper对象
    @Autowired
    private OperateLogMapper operateLogMapper;
    //切入点表达式
    @Pointcut("@annotation(com.itheima.annotation.Log)")
    private void pt(){}
    //通知：环绕通知
    @Around("pt()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        //日志信息包含：操作人、操作时间、执行方法的全类名、执行方法名、方法运行时参数、返回值、方法执行时长
        Long begin = System.currentTimeMillis();
        //目标类名
        String className = pjp.getTarget().getClass().getName();
        //目标方法名
        String methodName = pjp.getSignature().getName();
        //目标方法参数
        String params = Arrays.toString(pjp.getArgs());
        //执行原始方法
        Object result = pjp.proceed();
        Long end = System.currentTimeMillis();
        //把原始方法执行结果转换为String(json格式)
        String returnValue = JSONObject.toJSONString(result);
        //获取操作人：从HttpServletRequest请求头中获取token，然后解析
        String token = request.getHeader("token");
        Claims claims = JwtUtils.parseJWT(token);
        Integer id = (Integer) claims.get("id");//操作人ID
        log.info("运行耗时：{}毫秒",end-begin);
        //创建OperateLog对象
        OperateLog operateLog = new OperateLog();
        operateLog.setOperateTime(LocalDateTime.now());//操作时间
        operateLog.setCostTime(end-begin);//执行耗时
        operateLog.setOperateUser(id);//操作人
        operateLog.setClassName(className);//目标类名
        operateLog.setMethodName(methodName);//目标方法名
        operateLog.setMethodParams(params);//目标方法参数
        operateLog.setReturnValue(returnValue);//原始执行返回值

        //向操作日志表中添加数据
        operateLogMapper.insert(operateLog);


        //返回原始方法的执行结果
        return result;
    }
}
